package Eyjafjalla.monster;

import Eyjafjalla.action.MelodyAction;
import Eyjafjalla.modcore.EyjafjallaMod;
import Eyjafjalla.patch.MelodyPatch;
import Eyjafjalla.patch.SiestaPatch;
import Eyjafjalla.power.*;
import Eyjafjalla.subscriber.MelodySubscriber;
import com.megacrit.cardcrawl.actions.AbstractGameAction;
import com.megacrit.cardcrawl.actions.animations.TalkAction;
import com.megacrit.cardcrawl.actions.common.*;
import com.megacrit.cardcrawl.cards.DamageInfo;
import com.megacrit.cardcrawl.core.CardCrawlGame;
import com.megacrit.cardcrawl.core.Settings;
import com.megacrit.cardcrawl.dungeons.AbstractDungeon;
import com.megacrit.cardcrawl.localization.MonsterStrings;
import com.megacrit.cardcrawl.monsters.AbstractMonster;
import com.megacrit.cardcrawl.powers.*;
import com.megacrit.cardcrawl.unlock.UnlockTracker;

import java.util.ArrayList;

public class Dolly extends AbstractEyjafjallaMonster{
    public static final String ID = "eyjafjalla:Dolly";
    private static final String MID_PATH = "YZZ/enemy_1545_shpkg";
    private static final MonsterStrings monsterStrings;
    private static final EnemyType TYPE = EnemyType.BOSS;
    private static final String ATTACK_NAME = "Attack_A";
    private static final String IDLE_NAME = "Idle_A";
    private static final String DIE_NAME = "Die_B";
    private static final String SKILL_NAME = "Skill_A_1";

    public static final String ICON = "EyjafjallaResources/img/monster/YZZ/Dolly_Icon.png";
    public static final String ICON_O = "EyjafjallaResources/img/monster/YZZ/Dolly_Icon_O.png";

    static {
        monsterStrings = CardCrawlGame.languagePack.getMonsterStrings(ID);
    }

    int attack;
    int attack2;
    int attack_skill;
    int skill_times;
    int defend;
    int strength;
    int heal;
    int buffs;
    int debuffLevel;
    int melody;
    float waitTime = 0.3F;

    int lastHealth = 0;
    boolean damaged = false;

    RainByFire rbf;
    FireByRain fbr;

    boolean must4 = false;
    boolean must6 = false;

    boolean low = true;
    boolean low1 = false;
    boolean high1 = false;
    boolean initializeLow = false;
    boolean initializeHigh = false;

    public Dolly(float x, float y){
        super(monsterStrings.NAME,ID,TYPE,32,450F,450F,x,y);
        setSpine(MID_PATH,1.3F);
        setFastMode();
        this.state.setAnimation(0,IDLE_NAME,true);

        if(AbstractDungeon.ascensionLevel>=9){
            setHp(800);
        }
        else {
            setHp(720);
        }
        if(AbstractDungeon.ascensionLevel>=4){
            attack = 10;
            attack2 = 40;
            skill_times = 10;
        }
        else {
            attack = 8;
            attack2 = 32;
            skill_times = 8;
        }
        attack_skill = 4;
        if(AbstractDungeon.ascensionLevel>=19){
            defend = 60;
            strength = 18;
            heal = 60;
            buffs = 10;
            debuffLevel = 2;
            melody = 30;
            rbf = new RainByFire(10);
            fbr = new FireByRain(3);
        }
        else {
            defend = 40;
            strength = 12;
            heal = 40;
            buffs = 8;
            debuffLevel = 1;
            melody = 24;
            rbf = new RainByFire(8);
            fbr = new FireByRain(2);
        }
        low = true;
        initializeLow = false;
        initializeHigh = false;

        this.damage.add(new DamageInfo(this,this.attack, DamageInfo.DamageType.NORMAL));
        this.damage.add(new DamageInfo(this,this.attack2, DamageInfo.DamageType.NORMAL));
        this.damage.add(new DamageInfo(this,this.attack_skill, DamageInfo.DamageType.NORMAL));
    }

    public void setFastMode(){
        if(Settings.FAST_MODE){
            state.setTimeScale(2);
            this.waitTime = 0.15F;
        }
        else{
            state.setTimeScale(1);
            this.waitTime = 0.3F;
        }
    }

    @Override
    public void usePreBattleAction() {
        CardCrawlGame.music.unsilenceBGM();
        AbstractDungeon.scene.fadeOutAmbiance();
        SiestaPatch.BOSS_KEY = "DOLLY";
        AbstractDungeon.getCurrRoom().playBgmInstantly("BOSS_BEYOND");
        SiestaPatch.BOSS_KEY = "";

        addToBot(new ApplyPowerAction(this,this,new FluffShieldPower(this)));
        addToBot(new ApplyPowerAction(this,this,new MelodyMemoryPower(this,melody),melody));
        addToBot(new ApplyPowerAction(AbstractDungeon.player,AbstractDungeon.player,new PinkOceanPower(AbstractDungeon.player)));
        super.usePreBattleAction();
    }

    @Override
    protected void getMove(int i) {
        if(low){
            if(!initializeLow){
                low1 = i<50;
                initializeLow = true;
            }
        }
        else {
            if(!initializeHigh){
                high1 = i<50;
                initializeHigh = true;
            }
        }
        if(must4){
            setMove(monsterStrings.MOVES[3],(byte) 4,Intent.DEFEND_DEBUFF);
        }
        else if(must6){
            setMove(monsterStrings.MOVES[5],(byte) 6,Intent.ATTACK,damage.get(2).base,skill_times,true);
        }
        else {
            if(low){
                if(low1){
                    setMove(monsterStrings.MOVES[0],(byte) 1,Intent.ATTACK_DEBUFF,damage.get(0).base,3,true);
                }
                else {
                    setMove(monsterStrings.MOVES[1],(byte) 2,Intent.ATTACK_BUFF,damage.get(1).base);
                }
                low1 = !low1;
            }
            else {
                if(high1){
                    setMove(monsterStrings.MOVES[2],(byte) 3,Intent.BUFF);
                }
                else {
                    setMove(monsterStrings.MOVES[4],(byte) 5,Intent.BUFF);
                }
                high1 = !high1;
            }
            low = !low;
        }
    }

    @Override
    public void takeTurn() {
        setFastMode();
        switch (this.nextMove){
            case 1:{
                addToBot(new ChangeStateAction(this,"ATTACK"));
                for(int i =0;i<3;i++){
                    //effect todo
                    addToBot(new DamageAction(AbstractDungeon.player,damage.get(0), AbstractGameAction.AttackEffect.FIRE));
                }
                for(int i =0;i<buffs;i++){
                    addToBot(new ApplyPowerAction(AbstractDungeon.player,this,getRandomPower(true,1),1));
                }
                break;
            }
            case 2:{
                addToBot(new ChangeStateAction(this,"ATTACK"));
                addToBot(new DamageAction(AbstractDungeon.player,damage.get(1), AbstractGameAction.AttackEffect.BLUNT_HEAVY));
                for(int i =0;i<buffs;i++){
                    addToBot(new ApplyPowerAction(this,this,getRandomPower(false,1),1));
                }
                break;
            }
            case 3:{
                must4 = true;
                addToBot(new HealAction(this,this,heal));
                addToBot(new MelodyAction(rbf.getSingle()));
                break;
            }
            case 4:{
                must4 = false;
                addToBot(new GainBlockAction(this,defend));
                addToBot(new ApplyPowerAction(AbstractDungeon.player,this,new WhiteCloudPower(AbstractDungeon.player,debuffLevel),debuffLevel));
                addToBot(new ApplyPowerAction(AbstractDungeon.player,this,new RedCloudPower(AbstractDungeon.player,debuffLevel),debuffLevel));
                break;
            }
            case 5:{
                must6 = true;
                addToBot(new ApplyPowerAction(this,this,new StrengthPower(this,strength),strength));
                addToBot(new MelodyAction(fbr.getSingle()));
                break;
            }
            case 6:{
                must6 = false;
                addToBot(new ChangeStateAction(this,"SKILL"));
                for(int i =0;i<skill_times;i++){
                    //effect todo
                    addToBot(new DamageAction(AbstractDungeon.player,damage.get(2), AbstractGameAction.AttackEffect.FIRE));
                }
                break;
            }
        }

        addToBot(new RollMoveAction(this));
    }

    private AbstractPower getRandomPower(boolean debuff,int amount){
        AbstractPower p = null;
        int random = AbstractDungeon.monsterRng.random(4);
        if(debuff) {
            switch (random) {
                case 0:
                    p = new VulnerablePower(AbstractDungeon.player,amount,true);
                    break;
                case 1:
                    p = new WeakPower(AbstractDungeon.player,amount,true);
                    break;
                case 2:
                    p = new FrailPower(AbstractDungeon.player,amount,true);
                    break;
                case 3:
                    p = new WhiteCloudPower(AbstractDungeon.player,amount);
                    break;
                case 4:
                    p = new RedCloudPower(AbstractDungeon.player,amount);
                    break;
            }
        }
        else {
            switch (random) {
                case 0:
                    p = new PlatedArmorPower(this,amount);
                    break;
                case 1:
                    p = new MetallicizePower(this,amount);
                    break;
                case 2:
                    p = new RegenerateMonsterPower(this,amount);
                    break;
                case 3:
                    p = new ArtifactPower(this,amount);
                    break;
                case 4:
                    p = new MelodyMemoryPower(this,amount);
                    break;
            }
        }
        return p;
    }

    @Override
    public void changeState(String stateName) {
        switch (stateName){
            case "ATTACK":{
                this.state.setAnimation(0,ATTACK_NAME,false);
                this.state.addAnimation(0,IDLE_NAME,true,0F);
                break;
            }
            case "SKILL":{
                this.state.setAnimation(0,SKILL_NAME,false);
                this.state.addAnimation(0,IDLE_NAME,true,0F);
                break;
            }
            default:
                break;
        }
    }

    @Override
    public void update() {
        super.update();
        if(currentHealth>lastHealth){
            lastHealth = currentHealth;
        }
        else {
            if(damaged){
                damaged = false;
                lastHealth = currentHealth;
            }
            else if(currentHealth<lastHealth) {
                addToTop(new TalkAction(this, monsterStrings.DIALOG[5], 0.5F, 2.0F));
                currentHealth = lastHealth;
                healthBarUpdatedEvent();
            }
        }
    }

    @Override
    public void damage(DamageInfo info) {
        if(info.output==0&&lastHealth>currentHealth){
            addToTop(new TalkAction(this, monsterStrings.DIALOG[5], 0.5F, 2.0F));
            currentHealth = lastHealth;
            healthBarUpdatedEvent();
        }
        super.damage(info);
        damaged = true;
    }

    @Override
    public void die() {
        if (!AbstractDungeon.getCurrRoom().cannotLose) {
            this.useFastShakeAnimation(5.0F);
            CardCrawlGame.screenShake.rumble(4.0F);
            this.state.setTimeScale(1F);
            (AbstractDungeon.getCurrRoom()).rewardAllowed = false;
            state.setAnimation(0,DIE_NAME,false);
            super.die();
            this.onBossVictoryLogic();
            this.onFinalBossVictoryLogic();
            CardCrawlGame.stopClock = true;
        }
    }

    public class RainByFire implements MelodySubscriber {
        public RainByFire(int special){
            this.special = special;
        }

        int special;

        @Override
        public MelodyPatch.MelodySingle getSingle() {
            ArrayList<MelodyPatch.MelodyNote> notes = new ArrayList<>();
            notes.add(new MelodyPatch.MelodyNote(this,0,2,monsterStrings.DIALOG[0]+special+monsterStrings.DIALOG[1]));
            notes.add(new MelodyPatch.MelodyNote(this,1,2,monsterStrings.DIALOG[0]+special+monsterStrings.DIALOG[1]));
            notes.add(new MelodyPatch.MelodyNote(this,2,1,monsterStrings.DIALOG[0]+special+monsterStrings.DIALOG[1]));
            notes.add(new MelodyPatch.MelodyNote(this,3,1,monsterStrings.DIALOG[0]+special+monsterStrings.DIALOG[1]));
            notes.add(new MelodyPatch.MelodyNote(this,4,3,monsterStrings.DIALOG[0]+special+monsterStrings.DIALOG[1]));
            MelodyPatch.MelodySingle single = new MelodyPatch.MelodySingle(monsterStrings.DIALOG[3],notes,null);
            return single;
        }

        @Override
        public ArrayList<AbstractGameAction> getNoteActions(boolean isFinal, int specialAmount) {
            ArrayList<AbstractGameAction> actions = new ArrayList<>();
            for(AbstractMonster m: AbstractDungeon.getMonsters().monsters){
                EyjafjallaMod.logSomething("=== MONSTER ID :"+m.id+" ===");
                if(m.id.equals(Dolly.ID)){
                    actions.add(new LoseHPAction(m,m,specialAmount));
                }
            }
            return actions;
        }

        @Override
        public int initializeSpecialAmount(boolean isFinal) {
            return special;
        }
    }

    public class FireByRain implements MelodySubscriber{
        public FireByRain(int special){
            this.special = special;
        }

        int special;

        @Override
        public MelodyPatch.MelodySingle getSingle() {
            ArrayList<MelodyPatch.MelodyNote> notes = new ArrayList<>();
            notes.add(new MelodyPatch.MelodyNote(this,0,2,monsterStrings.DIALOG[0]+special+monsterStrings.DIALOG[2]));
            notes.add(new MelodyPatch.MelodyNote(this,1,2,monsterStrings.DIALOG[0]+special+monsterStrings.DIALOG[2]));
            notes.add(new MelodyPatch.MelodyNote(this,2,1,monsterStrings.DIALOG[0]+special+monsterStrings.DIALOG[2]));
            notes.add(new MelodyPatch.MelodyNote(this,3,1,monsterStrings.DIALOG[0]+special+monsterStrings.DIALOG[2]));
            notes.add(new MelodyPatch.MelodyNote(this,4,3,monsterStrings.DIALOG[0]+special+monsterStrings.DIALOG[2]));
            notes.add(new MelodyPatch.MelodyNote(this,5,3,monsterStrings.DIALOG[0]+special+monsterStrings.DIALOG[2]));
            MelodyPatch.MelodySingle single = new MelodyPatch.MelodySingle(monsterStrings.DIALOG[4],notes,null);
            return single;
        }

        @Override
        public ArrayList<AbstractGameAction> getNoteActions(boolean isFinal, int specialAmount) {
            ArrayList<AbstractGameAction> actions = new ArrayList<>();
            for(AbstractMonster m: AbstractDungeon.getMonsters().monsters){
                EyjafjallaMod.logSomething("=== MONSTER ID :"+m.id+" ===");
                if(m.id.equals(Dolly.ID)){
                    actions.add(new ApplyPowerAction(m,m,new StrengthPower(m,-specialAmount),-specialAmount));
                }
            }
            return actions;
        }

        @Override
        public int initializeSpecialAmount(boolean isFinal) {
            return special;
        }
    }
}

